#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include "Task.hpp"

const int NUM=6;

class ThreadPool
{
  private:
    int _num;//线程数
    bool stop;
    std::queue<Task> task_queue;
    pthread_mutex_t lock;
    pthread_cond_t cond;
    static ThreadPool* single_tp;//单例模式

  private:
    ThreadPool(int num=NUM)
      :_num(num)
      ,stop(false)
    {
      pthread_mutex_init(&lock,nullptr);
      pthread_cond_init(&cond,nullptr);
    }

    ThreadPool(const ThreadPool* tp)=delete;
    ThreadPool& operator=(const ThreadPool& tp)=delete;

  public:
    ~ThreadPool()
    {
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&cond);
    }

    static ThreadPool* GetInstance()
    {
      static pthread_mutex_t my_mutex=PTHREAD_MUTEX_INITIALIZER;
      if(single_tp==nullptr)
      {
        pthread_mutex_lock(&my_mutex);
        if(single_tp==nullptr)
        {
          single_tp=new ThreadPool();
          single_tp->InitThreadPool();
        }
        pthread_mutex_unlock(&my_mutex);
      }
      return single_tp;
    }
    
    bool IsStop()
    {
      return stop;
    }

    void PthreadWait()
    {
      pthread_cond_wait(&cond,&lock);
    }

    void PthreadWakeUp()
    {
      pthread_cond_signal(&cond);
    }

    void Lock()
    {
      pthread_mutex_lock(&lock);
    }

    void Unlock()
    {
      pthread_mutex_unlock(&lock);
    }

    bool TaskQueueIsEmpty()
    {
      return task_queue.empty();
    }

    static void* ThreadRoutine(void* args)
    {
      ThreadPool* tp=(ThreadPool*)args;
      while(true)
      {
        //线程执行逻辑
        Task t;
        tp->Lock();
        while(tp->TaskQueueIsEmpty())
        {
          tp->PthreadWait();
        }
        tp->PopTask(t);
        tp->Unlock();
        t.ProcessOn();
      }
    }

    bool InitThreadPool()
    {
      for(int i=0;i<=_num-1;i++)
      {
        pthread_t pid;
        if(0!=pthread_create(&pid,nullptr,ThreadRoutine,this))
        {
          LOG(FATAL,"create pthread pool fail");
          return false;
        }
      }

      LOG(INFO,"create pthread pool success");
      return true;
    }

    void PushTask(const Task& task)//in
    {
      Lock();
      task_queue.push(task);
      Unlock();
      PthreadWakeUp();
    }

    void PopTask(Task& task)//out
    {
      task=task_queue.front();
      task_queue.pop();
    }
};
ThreadPool* ThreadPool::single_tp=nullptr;
